有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在代码中滚动滚动窗格?

我正试图在LibGDX中创建一个类似于这样的滚轮组件: enter image description here

我使用ScrollPane,因为它内置了输入和抛出处理。我有一个滚轮的图像,它分为14个部分,滚动窗格本身缩短了两个部分,因此在左右两侧各有一个部分,可以向任意方向滚动。一旦滚动位置到达任一方向的末端,我想将滚动位置重置回中心。一遍又一遍地这样做会产生一种无限滚动的幻觉(希望如此)

我遇到的问题是如何在代码中定位滚动窗格,以便在图像到达任意一端时重置图像。到目前为止,我尝试设置滚动位置的任何操作都不起作用。我尝试过setScrollX()和scrollTo()方法。我还尝试将滚动窗格的大小设置为各种大小(与图像大小相同,并且比图像小两部分)。在设置滚动值之前,我尝试在滚动窗格上调用layout、invalidate和pack,以确保其布局正确。我认为updateVisualScroll()可能会强制它更新滚动位置,但这也没有效果

无论我做什么,它都会忽略所有更改滚动位置的调用,因此我显然遗漏了一些内容。在下面的代码中,我试图让滚轮从图像的中心开始,相反,它的开始位置一直在左边

我还需要能够得到当前的滚动位置,以检测何时它已达到任一端。我尝试重写act()方法并打印出scrollPane。getX(),但即使手动单击并拖动该值以滚动滚动滚动窗格,该值始终为“0”

手动单击和拖动时,滚动确实有效,因此我相信滚动窗格设置正确,我只是无法让它在代码中滚动

这是我的代码,为了简单起见,我去掉了所有的实验代码,因为我的实验都不起作用

public class MyScrollWheel extends Container<ScrollPane> {
    private ScrollPane scrollPane;
    private Image image;
    private int scrollOffset;

    public MyScrollWheel(){
        Texture texture = new Texture(Gdx.files.internal("internal/scrollwheel.png"));
        image = new Image(texture);

        scrollOffset = (int)(image.getWidth()/14);

        scrollPane = new ScrollPane(image);
        scrollPane.setOverscroll(false, false);

        setActor(scrollPane);
        size(image.getWidth()-(scrollOffset*2), image.getHeight());

        scrollPane.setScrollX(scrollOffset); // << this doesn't scroll
        scrollPane.updateVisualScroll();
    }
}

共 (2) 个答案

  1. # 1 楼答案

    扩展Menno Gouw的滚轮,我添加了更多功能:

    • 投掷支撑,设置投掷时间
    • 调整车轮灵敏度的精密设置
    • 需要一个可拖动的
    • 兼容在滚动窗格中使用

    注意:出于我的目的,我在构造函数中使用了一个标签,但是如果不想将它绑定到标签上,可以很容易地更改它

    下面是我在手机上录制的演示滚轮的视频

    https://www.youtube.com/watch?v=RwVrez4BZsY&feature=youtu.be

    -编辑1:布局错误现在已经修复(希望如此)。现在,当在滚动窗格中移动时,它会更新其位置,可绘制的内容会被剪切到演员的边框上

    -编辑2:增加了对固定可绘制阴影的支持,以及改变方向盘方向的方法(setRightPositiveDirection())

    public class ScrollWheel extends Actor {
        private Drawable wheelDrawable, wheelShading;
        private Label label;
    
        private int unscaledScrollValueX=0, scrollValueX=0;
        private boolean isNotEdge;
        private int precision=40;
        private int direction=1;
        private int minValue=Integer.MIN_VALUE, maxValue=Integer.MAX_VALUE;
        // MANUAL SCROLL
        private int separator;
        private int wheelWidth;
        // FLING
        private float flingTimer, flingTime=1f;
        private float velocityX;
    
        public ScrollWheel(Drawable wheelDrawable, Drawable wheelShading, Label label) {
            this.wheelDrawable = wheelDrawable;
            this.wheelShading = wheelShading;
            this.label = label;
    
            wheelWidth = (int)wheelDrawable.getMinWidth();
            separator = wheelWidth;
    
            setWidth(wheelDrawable.getMinWidth());
            setHeight(wheelDrawable.getMinHeight());
    
            // stops ScrollPane from overriding input events
            InputListener stopTouchDown = new InputListener() {
                public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    event.stop();
                    return false;
                }
            };
            addListener(stopTouchDown);
    
            ActorGestureListener flickScrollListener = new ActorGestureListener() {
                public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
                    updateScroll(deltaX);
                }
                public void fling (InputEvent event, float x, float y, int button) {
                    if (Math.abs(x) > 150) {
                        flingTimer = flingTime;
                        velocityX = x;
                    }
                }
                public boolean handle (Event event) {
                    if (super.handle(event)) {
                        if (((InputEvent)event).getType() == InputEvent.Type.touchDown) flingTimer = 0;
                        return true;
                    }
                    return false;
                }
            };
            addListener(flickScrollListener);
        }
    
        private void updateScroll(float delta){
            unscaledScrollValueX += (delta * direction);
            scrollValueX = (int)(unscaledScrollValueX / precision);
    
            isNotEdge = true;
            if (scrollValueX <= minValue){
                scrollValueX = minValue;
                unscaledScrollValueX = minValue * precision;
                isNotEdge = false;          
            }
            else if (scrollValueX >= maxValue){
                scrollValueX = maxValue;
                unscaledScrollValueX = maxValue * precision;
                isNotEdge = false;          
            }
            if (isNotEdge){         
                separator += delta;
                if (separator <= 0){
                    separator = wheelWidth;
                }
                else if (separator >= wheelWidth) {
                    separator = 0;
                }
            }
    
            updateLabel();      
        }
        private void updateLabel(){
            label.setText("" + scrollValueX);   
        }
    
        public void setMinValue(int minValue){ this.minValue = minValue; }
        public void setMinValueToNone(){ minValue=Integer.MIN_VALUE; }
        public void setMaxValue(int maxValue){ this.maxValue = maxValue; }
        public void setMaxValueToNone(){ minValue=Integer.MAX_VALUE; }
        public void setFlingTime(float flingTime){ this.flingTime = flingTime; }
        public void setPrecision(int precision){ this.precision = precision; }
        public void setRightPositiveDirection(boolean rightPositive){ direction = (rightPositive) ? 1 : -1; }
    
        @Override
        public void act(float delta){
            super.act(delta);
    
            boolean animating = false;
            if (flingTimer > 0) {
                float alpha = flingTimer / flingTime;
                updateScroll(velocityX * alpha * delta);
    
                flingTimer -= delta;
                if (flingTimer <= 0) {
                    velocityX = 0;
                }
                animating = true;
            }
    
            if (animating) {
                Stage stage = getStage();
                if (stage != null && stage.getActionsRequestRendering()){
                    Gdx.graphics.requestRendering();
                }
            }
        }
    
        @Override
        public void draw(Batch batch, float parentAlpha){
            super.draw(batch, parentAlpha);
            batch.flush();
            if (clipBegin(getX(), getY(), getWidth(), getHeight())){
                wheelDrawable.draw(batch, getX() + separator - wheelWidth, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());      
                wheelDrawable.draw(batch, getX() + separator, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
                wheelShading.draw(batch, getX(), getY(), wheelShading.getMinWidth(), wheelShading.getMinHeight());
                batch.flush();
                clipEnd();
            }
        }
    }
    
  2. # 2 楼答案

    好吧,我希望能得到一些你可以借鉴的东西。我只是扩展了actor,让它接受纹理,这样我就可以使用纹理了。用SpriteBatch.draw()包装并绘制。我现在可以继续滚动它,根据滚动增量,你可以计算出它被滚动了多远。我看不出有任何必要重置方向盘,但如果你真的想重置,你可以执行wheel.setScroll(0);

    一个限制是它不是Drawable,因此不能像NinePatch那样缩放。你必须给它一个普通的轮子纹理,画出你想要的大小,你可以添加普通的缩放,但是手动保持纵横比。然后添加边,也许在这些边上叠加一个渐变来创造深度

    滚轮:

    public class ScrollWheel extends Actor {
        Texture wheelTexture;
        private int scroll = 0;
    
        public int getScroll() {
            return scroll;
        }
        public void setScroll(int scroll) {
            this.scroll = scroll;
        }
    
        public ScrollWheel(Texture texture)
        {
            wheelTexture = texture;
            wheelTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
    
            setWidth(texture.getWidth());
            setHeight(texture.getHeight());
        }
    
        @Override
        public void draw(Batch batch, float parentAlpha) {
            super.draw(batch, parentAlpha);
    
            batch.draw(wheelTexture, getX(), getY(), scroll, 0,
                    wheelTexture.getWidth(), wheelTexture.getHeight());
        }
    }
    

    屏幕中的用法:

    public class TestScreen implements Screen {
        Stage stage;
        ScrollWheel wheel;
    
        public TestScreen() {
            stage = new Stage();
            Table t = new Table();
            t.setFillParent(true);
            stage.addActor(t);
    
            wheel = new ScrollWheel(new Texture("hud/wheel_part.png"));
            wheel.addListener(new DragListener() {
                @Override
                public void drag(InputEvent event, float x, float y, int pointer) {
                    super.drag(event, x, y, pointer);
                    wheel.setScroll(wheel.getScroll() + (int)getDeltaX());
                }
            });
    
            t.add(wheel);
            Gdx.input.setInputProcessor(stage);
        }
    
        @Override
        public void render(float delta) {
            Gdx.gl.glClearColor(.3f, .36f, .42f, 1);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
            stage.act();
            stage.draw();
        }
        //...Other mandatory screen methods...
    }
    

    因此,只需创建一个可耕的轮子纹理,并将其包含在ScrollWheel构造器中。如果你使用这个精确的代码,它会在屏幕中央画轮子

    变量scroll基本上保存了滚动量,因此如果您想将其限制在0到100之间,只需在setScroll()中添加此功能即可

    if (scroll > 100) scroll = 100; 
    else if (scroll < 0) scroll = 0;
    

    然后你可以添加一个步骤。因此,如果你想用滑块旋转图像,你可以通过scroll * 3,6fscroll * (maxScroll / maxStep)来设置旋转

    我真的很喜欢这个结果,我将在未来使用这个滑块:D。我已经对它进行了一些扩展和修改,您可以在这里看到我的实现:https://youtu.be/RNLk5B-VfYg